#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <signal.h>
#include <stdint.h>
#include <sys/wait.h>
#include <pthread.h>  // 新增：线程头文件
#include "../server/media_lib.h"       // 引入mlib_list_entry定义和BUFSIZE
#include "../proto/netradio_proto.h"

// -------------------------- 全局变量 --------------------------
static int multicast_fd = -1;    // 多播接收Socket
static pid_t mplayer_pid = -1;   // mplayer子进程ID
static int audio_pipe[2] = {-1}; // 音频数据管道（父写子读）
static chnid_t selected_chn = 0; // 用户选择的频道ID
static int client_running = 1;   // 客户端运行标志（原client_exit是变量名错误）


// -------------------------- 信号处理（优雅退出） --------------------------
void sig_handler(int sig) {
    if (sig == SIGINT) {
        printf("\nClient is exiting...\n");
        client_running = 0;

        // 关闭管道写端
        if (audio_pipe[1] != -1) {
            close(audio_pipe[1]);
            audio_pipe[1] = -1;
        }

        // 终止mplayer子进程
        if (mplayer_pid != -1) {
            kill(mplayer_pid, SIGTERM);
            waitpid(mplayer_pid, NULL, 0);
            mplayer_pid = -1;
        }

        // 关闭多播Socket
        if (multicast_fd != -1) {
            close(multicast_fd);
            multicast_fd = -1;
        }

        exit(0);
    }
}


// -------------------------- 多播Socket初始化（核心修复） --------------------------
int multicast_socket_init(void) {
    struct sockaddr_in addr;
    struct ip_mreq mreq;
    int opt_val = 1;
    const char *ens33_ip = "192.168.101.134"; // 接收网卡（ens33）的当前IP
    const char *mcast_group = GROUP_ADDR;     // 多播组地址（239.23.32.99）

    // 1. 创建UDP Socket
    multicast_fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (multicast_fd < 0) {
        perror("[Client] socket create failed");
        return -1;
    }
    printf("[Client] Socket created (fd: %d)\n", multicast_fd);

    // 2. 允许端口重用（避免“地址已占用”错误）
    if (setsockopt(multicast_fd, SOL_SOCKET, SO_REUSEADDR, 
        &opt_val, sizeof(opt_val)) < 0) {
        perror("[Client] setsockopt SO_REUSEADDR failed");
        close(multicast_fd);
        return -1;
    }

    // 3. 开启多播环回（同一台机器发送/接收必须开启）
    int loop = 1;
    if (setsockopt(multicast_fd, IPPROTO_IP, IP_MULTICAST_LOOP, 
        &loop, sizeof(loop)) < 0) {
        perror("[Client] setsockopt IP_MULTICAST_LOOP failed");
        close(multicast_fd);
        return -1;
    }
    printf("[Client] IP_MULTICAST_LOOP enabled (support local receive)\n");

    // 4. 绑定多播端口（仅绑定端口，地址用INADDR_ANY）
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(RCV_PORT);          // 绑定6666端口
    addr.sin_addr.s_addr = htonl(INADDR_ANY); // 接收所有网卡的该端口数据
    if (bind(multicast_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
        perror("[Client] bind to port 6666 failed");
        close(multicast_fd);
        return -1;
    }
    printf("[Client] Bound to port %d\n", RCV_PORT);

    // 5. 配置多播组（关键：加入239.23.32.99组，指定ens33网卡接收）
    // 5.1 设置多播组地址
    if (inet_pton(AF_INET, mcast_group, &mreq.imr_multiaddr) <= 0) {
        fprintf(stderr, "[Client] Invalid multicast group: %s\n", mcast_group);
        close(multicast_fd);
        return -1;
    }
    // 5.2 设置接收网卡（ens33）
    struct in_addr iface_addr;
    if (inet_pton(AF_INET, ens33_ip, &iface_addr) <= 0) {
        fprintf(stderr, "[Client] Invalid ens33 IP: %s, use INADDR_ANY instead\n", ens33_ip);
        iface_addr.s_addr = htonl(INADDR_ANY); // 自动选择网卡
    }
    mreq.imr_interface = iface_addr;

    // 6. 加入多播组（核心操作）
    if (setsockopt(multicast_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, 
        &mreq, sizeof(mreq)) < 0) {
        perror("[Client] setsockopt IP_ADD_MEMBERSHIP failed");
        close(multicast_fd);
        return -1;
    }

    // 初始化成功日志（修正为Client，避免混淆）
    printf("Multicast socket ready (listening on %s:%d, interface: %s)\n", 
           mcast_group, RCV_PORT, ens33_ip);
    return 0;
}


// -------------------------- 频道列表解析 --------------------------
int parse_chn_list(struct mlib_list_entry **chn_list, int *chn_count) {
    char recv_buf[1024];
    memset(recv_buf, 0, sizeof(recv_buf));
    struct sockaddr_in src_addr;
    socklen_t addr_len = sizeof(src_addr);
    int recv_len;
    char *ptr = NULL;
    int list_count = 0;

    printf("Waiting for channel list from server...\n");
    printf("(Note: If receiving audio data first, please wait...)\n"); // 新增提示
    int wait_cnt = 0;

    // 延长超时时间到2秒（原1秒）
    struct timeval tv = {2, 0};
    if (setsockopt(multicast_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
        perror("[Client] setsockopt SO_RCVTIMEO failed");
        return -1;
    }

    while (wait_cnt < 10) {
        printf("[Client] 第%d次尝试接收（剩余%d次）...\n", wait_cnt+1, 10-wait_cnt);
        recv_len = recvfrom(multicast_fd, recv_buf, sizeof(recv_buf)-1, 0,
                          (struct sockaddr *)&src_addr, &addr_len);
        
        if (recv_len < 0) {
            if (errno == EAGAIN || errno == EWOULDBLOCK) {
                printf("[Client] 接收超时（2秒）\n");
                wait_cnt++;
                continue;
            }
            perror("[Client] recvfrom failed");
            return -1;
        }

        union chn_recv_st *recv_data = (union chn_recv_st *)recv_buf;
        if (recv_data->chnid != CHN_LIST_ID) {
            // 新增：提示收到的是哪个频道的音频包
            printf("[Client] 收到频道%d的音频包（首字节=%d≠0），跳过\n", 
                   recv_data->chnid, recv_data->chnid);
            wait_cnt++;
            continue;
        }

        // 2. 解析所有list_entry（从首字节后开始）
        ptr = recv_buf + sizeof(chnid_t);  // 跳过首字节（CHN_LIST_ID）
        int remain_len = recv_len - sizeof(chnid_t);  // 剩余待解析长度

        // 先统计频道数量
        while (remain_len > 0) {
            // 检查剩余长度是否足够容纳list_entry头部（1+1=2字节）
            if (remain_len < sizeof(struct list_entry)) {
                fprintf(stderr, "[Client] 频道列表数据不完整（剩余%d字节<2字节）\n", remain_len);
                return -1;
            }
            struct list_entry *entry = (struct list_entry *)ptr;

            // 检查entry->len是否合法（不能超过剩余长度）
            if (entry->len <= 0 || entry->len > remain_len) {
                fprintf(stderr, "[Client] 无效的条目长度：%d字节（剩余%d字节）\n", entry->len, remain_len);
                return -1;
            }

            list_count++;
            ptr += entry->len;          // 按entry->len跳过当前条目
            remain_len -= entry->len;   // 更新剩余长度
        }

        // 3. 分配频道列表内存
        *chn_list = (struct mlib_list_entry *)calloc(list_count, sizeof(struct mlib_list_entry));
        if (*chn_list == NULL) {
            perror("[Client] 分配频道列表内存失败");
            return -1;
        }
        *chn_count = list_count;

        // 4. 重新解析，提取频道信息
        ptr = recv_buf + sizeof(chnid_t);
        remain_len = recv_len - sizeof(chnid_t);
        for (int i = 0; i < list_count; i++) {
            struct list_entry *entry = (struct list_entry *)ptr;
            (*chn_list)[i].chnid = entry->chnid;
            (*chn_list)[i].descr = strdup(entry->descr);  // 复制描述（含'\0'）

            if ((*chn_list)[i].descr == NULL) {
                perror("[Client] 复制频道描述失败");
                for (int j = 0; j < i; j++) free((*chn_list)[j].descr);
                free(*chn_list);
                return -1;
            }

            printf("[Client] 解析到频道：ID=%d，描述=%s，条目长度=%d字节\n",
                   entry->chnid, entry->descr, entry->len);
            ptr += entry->len;
            remain_len -= entry->len;
        }

        printf("Successfully received %d channels\n", list_count);
        return 0;
    }

    fprintf(stderr, "Timeout: No channel list received\n");
    return -1;
}


// -------------------------- 用户频道选择 --------------------------
chnid_t select_channel(struct mlib_list_entry *chn_list, int chn_count) {
    int input;

    printf("\n==================== Channel List ====================\n");
    for (int i = 0; i < chn_count; i++) {
        printf("  Channel %d: %s", chn_list[i].chnid, chn_list[i].descr);
        if (chn_list[i].descr[strlen(chn_list[i].descr)-1] == '\n') {
            printf("\b");
        }
        printf("\n");
    }
    printf("======================================================\n");

    while (1) {
        printf("Please enter the channel ID you want to listen to: ");
        if (scanf("%d", &input) != 1) {
            while (getchar() != '\n');
            fprintf(stderr, "Invalid input! Please enter a number.\n");
            continue;
        }

        int valid = 0;
        for (int i = 0; i < chn_count; i++) {
            if (chn_list[i].chnid == input) {
                valid = 1;
                break;
            }
        }
        if (valid) {
            return input;
        } else {
            fprintf(stderr, "Invalid channel ID! Please choose from the list.\n");
        }
    }
}


// -------------------------- 音频播放（启动mplayer） --------------------------
int start_mplayer(void) {
    if (pipe(audio_pipe) < 0) {
        perror("pipe create failed");
        return -1;
    }

    mplayer_pid = fork();
    if (mplayer_pid < 0) {
        perror("fork failed");
        close(audio_pipe[0]);
        close(audio_pipe[1]);
        audio_pipe[0] = audio_pipe[1] = -1;
        return -1;
    }

    // 子进程：启动MPlayer（强制音频格式+禁用视频+忽略错误）
    if (mplayer_pid == 0) {
        close(audio_pipe[1]);
        if (dup2(audio_pipe[0], STDIN_FILENO) < 0) {
			perror("dup2 failed");
			exit(1);
		}
		close(audio_pipe[0]);
		execlp("mplayer", "mplayer", "-quiet", "-cache", "4096", "-cache-min", "5",
        		"-demuxer", "lavf", "-novideo", "-", NULL);
        perror("execlp mplayer failed (install mplayer first)");
        exit(1);
    }

    // 父进程：关闭读端
    close(audio_pipe[0]);
    printf("Mplayer started (PID: %d). Listening to channel %d...\n", mplayer_pid, selected_chn);
    printf("Press Ctrl+C to exit.\n");
    return 0;
}

// -------------------------- 音频数据接收与过滤（线程函数） --------------------------
void *recv_and_play_audio(void *arg) {
    // 无需定义局部变量！直接使用全局selected_chn（已在main中赋值）
    char recv_buf[4096];
    struct sockaddr_in src_addr;
    socklen_t addr_len = sizeof(src_addr);
    ssize_t recv_len;

    while (client_running) {
        recv_len = recvfrom(multicast_fd, recv_buf, sizeof(recv_buf)-1, 0,
                          (struct sockaddr *)&src_addr, &addr_len);
        if (recv_len < 0) {
            if (errno == EINTR) continue;
            perror("[Client] recvfrom failed");
            break;
        }

        // 直接使用全局变量selected_chn过滤频道
        chnid_t pkt_chnid = (chnid_t)recv_buf[0];
        size_t mp3_data_len = recv_len - 1;
        char *mp3_data = recv_buf + 1;

        if (pkt_chnid == selected_chn) {  // 现在能正确匹配选中频道
            if (write(audio_pipe[1], mp3_data, mp3_data_len) != mp3_data_len) {
                perror("[Client] write to mplayer failed");
                break;
            }
        }
    }
    return NULL;
}

// -------------------------- 主函数 --------------------------
int main(void) {
    struct mlib_list_entry *chn_list = NULL;
    int chn_count = 0;
    pthread_t recv_thread;  // 新增：接收数据的线程ID

    // 注册信号处理
    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = sig_handler;
    sigemptyset(&sa.sa_mask);
    if (sigaction(SIGINT, &sa, NULL) < 0) {
        perror("sigaction failed");
        return -1;
    }

    // 初始化多播Socket
    if (multicast_socket_init() < 0) {
        fprintf(stderr, "Multicast socket init failed\n");
        return -1;
    }

    // 解析频道列表
    if (parse_chn_list(&chn_list, &chn_count) < 0) {
        fprintf(stderr, "Parse channel list failed\n");
        close(multicast_fd);
        return -1;
    }

    // 选择频道
    selected_chn = select_channel(chn_list, chn_count);
    // 释放频道列表
    for (int i = 0; i < chn_count; i++) {
        free(chn_list[i].descr);
    }
    free(chn_list);

    // 启动播放
    if (start_mplayer() < 0) {
        fprintf(stderr, "Start mplayer failed\n");
        close(multicast_fd);
        return -1;
    }

    // 修复：创建线程启动接收逻辑（避免阻塞主进程）
    if (pthread_create(&recv_thread, NULL, recv_and_play_audio, NULL) != 0) {
        perror("pthread_create recv_thread failed");
        close(audio_pipe[1]);
        kill(mplayer_pid, SIGTERM);
        close(multicast_fd);
        return -1;
    }

    // 主进程：等待线程结束（或保持运行，直到收到退出信号）
    pthread_join(recv_thread, NULL);

    // 清理资源
    if (audio_pipe[1] != -1) close(audio_pipe[1]);
    if (mplayer_pid != -1) {
        kill(mplayer_pid, SIGTERM);
        waitpid(mplayer_pid, NULL, 0);
    }
    if (multicast_fd != -1) close(multicast_fd);

    printf("Client exited successfully\n");
    return 0;
}